Išsamus vadovas, skirtas suprasti ir įgyvendinti TypeScript tarpinę programinę įrangą Express.js programose. Išnagrinėkite pažangius tipo šablonus, kad kodas būtų patikimas ir lengvai prižiūrimas.
TypeScript Middleware: Mastering Express Middleware Type Patterns
Express.js, minimalistinis ir lankstus Node.js internetinių programų kūrimo karkasas, leidžia kūrėjams kurti patikimas ir keičiamo dydžio API ir internetines programas. TypeScript patobulina Express, pridėdamas statinį tipavimą, pagerindamas kodo priežiūrą ir anksti pagaudamas klaidas. Tarpinės programinės įrangos funkcijos yra Express pagrindas, leidžiantis jums perimti ir apdoroti užklausas prieš joms pasiekiant maršruto tvarkykles. Šiame straipsnyje nagrinėjami pažangūs TypeScript tipo šablonai, skirti apibrėžti ir naudoti Express tarpinę programinę įrangą, didinant tipo saugumą ir kodo aiškumą.
Understanding Express Middleware
Tarpinės programinės įrangos funkcijos yra funkcijos, kurios turi prieigą prie užklausos objekto (req), atsako objekto (res) ir kitos tarpinės programinės įrangos funkcijos programos užklausos-atsako cikle. Tarpinės programinės įrangos funkcijos gali atlikti šias užduotis:
- Vykdyti bet kokį kodą.
- Atlikti pakeitimus užklausos ir atsako objektuose.
- Užbaigti užklausos-atsako ciklą.
- Iškvieti kitą tarpinės programinės įrangos funkciją rietuvėje.
Tarpinės programinės įrangos funkcijos vykdomos nuosekliai, kai jos pridedamos prie Express programos. Dažniausi tarpinės programinės įrangos naudojimo atvejai apima:
- Užklausų registravimą.
- Vartotojų autentifikavimą.
- Autorizavimo prieigą prie išteklių.
- Užklausos duomenų patvirtinimą.
- Klaidų apdorojimą.
Basic TypeScript Middleware
Pagrindinėje TypeScript Express programoje tarpinės programinės įrangos funkcija gali atrodyti taip:
import { Request, Response, NextFunction } from 'express';
function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
console.log(`Request: ${req.method} ${req.url}`);
next();
}
export default loggerMiddleware;
Ši paprasta tarpinė programinė įranga įrašo užklausos metodą ir URL į konsolę. Išskaidykime tipo anotacijas:
Request: atspindi Express užklausos objektą.Response: atspindi Express atsako objektą.NextFunction: funkcija, kuri, iškvietus, vykdo kitą tarpinę programinę įrangą rietuvėje.
Galite naudoti šią tarpinę programinę įrangą savo Express programoje taip:
import express from 'express';
import loggerMiddleware from './middleware/loggerMiddleware';
const app = express();
const port = 3000;
app.use(loggerMiddleware);
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Advanced Type Patterns for Middleware
Nors pagrindinis tarpinės programinės įrangos pavyzdys yra funkcionalus, jam trūksta lankstumo ir tipo saugumo sudėtingesniems scenarijams. Išnagrinėkime pažangius tipo šablonus, kurie patobulina tarpinės programinės įrangos kūrimą su TypeScript.
1. Custom Request/Response Types
Dažnai jums reikės išplėsti Request arba Response objektus pasirinktinėmis savybėmis. Pavyzdžiui, po autentifikavimo galite norėti pridėti user savybę prie Request objekto. TypeScript leidžia jums papildyti esamus tipus naudojant deklaracijų suliejimą.
// src/types/express/index.d.ts
import { Request as ExpressRequest } from 'express';
declare global {
namespace Express {
interface Request {
user?: {
id: string;
email: string;
// ... other user properties
};
}
}
}
export {}; // This is needed to make the file a module
Šiame pavyzdyje mes papildome Express.Request sąsają, kad įtrauktume neprivalomą user savybę. Dabar, savo autentifikavimo tarpinėje programinėje įrangoje, galite užpildyti šią savybę:
import { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Simulate authentication logic
const userId = req.headers['x-user-id'] as string; // Or fetch from a token, etc.
if (userId) {
// In a real application, you would fetch the user from a database
req.user = {
id: userId,
email: `user${userId}@example.com`
};
next();
} else {
res.status(401).send('Unauthorized');
}
}
export default authenticationMiddleware;
Ir savo maršruto tvarkyklėse galite saugiai pasiekti req.user savybę:
import express from 'express';
import authenticationMiddleware from './middleware/authenticationMiddleware';
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/profile', (req: Request, res: Response) => {
if (req.user) {
res.send(`Hello, ${req.user.email}! Your user ID is ${req.user.id}`);
} else {
// This should never happen if the middleware is working correctly
res.status(500).send('Internal Server Error');
}
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
2. Middleware Factories
Middleware factories yra funkcijos, kurios grąžina tarpinės programinės įrangos funkcijas. Šis šablonas yra naudingas, kai reikia sukonfigūruoti tarpinę programinę įrangą su konkrečiomis parinktimis ar priklausomybėmis. Pavyzdžiui, apsvarstykite registravimo tarpinę programinę įrangą, kuri registruoja pranešimus į konkretų failą:
import { Request, Response, NextFunction } from 'express';
import fs from 'fs';
import path from 'path';
function createLoggingMiddleware(logFilePath: string) {
return (req: Request, res: Response, next: NextFunction) => {
const logMessage = `[${new Date().toISOString()}] Request: ${req.method} ${req.url}\n`;
fs.appendFile(logFilePath, logMessage, (err) => {
if (err) {
console.error('Error writing to log file:', err);
}
next();
});
};
}
export default createLoggingMiddleware;
Galite naudoti šią tarpinės programinės įrangos gamyklą taip:
import express from 'express';
import createLoggingMiddleware from './middleware/loggingMiddleware';
const app = express();
const port = 3000;
const logFilePath = path.join(__dirname, 'logs', 'requests.log');
app.use(createLoggingMiddleware(logFilePath));
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
3. Asynchronous Middleware
Tarpinės programinės įrangos funkcijos dažnai turi atlikti asinchronines operacijas, tokias kaip duomenų bazės užklausos arba API iškvietimai. Norėdami tinkamai apdoroti asinchronines operacijas, turite užtikrinti, kad funkcija next būtų iškviesta po to, kai bus baigta asinchroninė operacija. Tai galite pasiekti naudodami async/await arba pažadus.
import { Request, Response, NextFunction } from 'express';
async function asyncMiddleware(req: Request, res: Response, next: NextFunction) {
try {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Asynchronous operation completed');
next();
} catch (error) {
next(error); // Pass the error to the error handling middleware
}
}
export default asyncMiddleware;
Svarbu: nepamirškite apdoroti klaidų savo asinchroninėje tarpinėje programinėje įrangoje ir perduoti jas klaidų apdorojimo tarpinei programinei įrangai naudodami next(error). Tai užtikrina, kad klaidos bus tinkamai apdorotos ir įrašytos.
4. Error Handling Middleware
Klaidų apdorojimo tarpinė programinė įranga yra specialus tarpinės programinės įrangos tipas, kuris apdoroja klaidas, įvykusias užklausos-atsako ciklo metu. Klaidų apdorojimo tarpinės programinės įrangos funkcijos turi keturis argumentus: err, req, res ir next.
import { Request, Response, NextFunction } from 'express';
function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
console.error(err.stack);
res.status(500).send('Something went wrong!');
}
export default errorHandler;
Turite užregistruoti klaidų apdorojimo tarpinę programinę įrangą po visos kitos tarpinės programinės įrangos ir maršruto tvarkyklių. Express identifikuoja klaidų apdorojimo tarpinę programinę įrangą pagal keturių argumentų buvimą.
import express from 'express';
import asyncMiddleware from './middleware/asyncMiddleware';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(asyncMiddleware);
app.get('/', (req, res) => {
throw new Error('Simulated error!'); // Simulate an error
});
app.use(errorHandler); // Error handling middleware MUST be registered last
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
5. Request Validation Middleware
Užklausų patvirtinimas yra labai svarbus kuriant saugias ir patikimas API. Tarpinė programinė įranga gali būti naudojama gaunamiems užklausų duomenims patvirtinti ir užtikrinti, kad jie atitiktų tam tikrus kriterijus, prieš jiems pasiekiant jūsų maršruto tvarkykles. Bibliotekos, tokios kaip joi arba express-validator, gali būti naudojamos užklausų patvirtinimui.
Štai pavyzdys naudojant express-validator:
import { Request, Response, NextFunction } from 'express';
import { body, validationResult } from 'express-validator';
const validateCreateUserRequest = [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
export default validateCreateUserRequest;
Ši tarpinė programinė įranga patvirtina email ir password laukus užklausos tekste. Jei patvirtinimas nepavyksta, ji grąžina 400 Bad Request atsakymą su klaidų pranešimų masyvu. Galite naudoti šią tarpinę programinę įrangą savo maršruto tvarkyklėse taip:
import express from 'express';
import validateCreateUserRequest from './middleware/validateCreateUserRequest';
const app = express();
const port = 3000;
app.post('/users', validateCreateUserRequest, (req, res) => {
// If validation passes, create the user
res.send('User created successfully!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
6. Dependency Injection for Middleware
Kai jūsų tarpinės programinės įrangos funkcijos priklauso nuo išorinių paslaugų ar konfigūracijų, priklausomybių įterpimas gali padėti pagerinti testavimą ir priežiūrą. Galite naudoti priklausomybių įterpimo konteinerį, pvz., tsyringe, arba tiesiog perduoti priklausomybes kaip argumentus savo tarpinės programinės įrangos gamykloms.
Štai pavyzdys, naudojant tarpinės programinės įrangos gamyklą su priklausomybių įterpimu:
// src/services/UserService.ts
export class UserService {
async createUser(email: string, password: string): Promise {
// In a real application, you would save the user to a database
console.log(`Creating user with email: ${email} and password: ${password}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate a database operation
}
}
// src/middleware/createUserMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/UserService';
function createCreateUserMiddleware(userService: UserService) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const { email, password } = req.body;
await userService.createUser(email, password);
res.status(201).send('User created successfully!');
} catch (error) {
next(error);
}
};
}
export default createCreateUserMiddleware;
// src/app.ts
import express from 'express';
import createCreateUserMiddleware from './middleware/createUserMiddleware';
import { UserService } from './services/UserService';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(express.json()); // Parse JSON request bodies
const userService = new UserService();
const createUserMiddleware = createCreateUserMiddleware(userService);
app.post('/users', createUserMiddleware);
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Best Practices for TypeScript Middleware
- Keep middleware functions small and focused. Each middleware function should have a single responsibility.
- Use descriptive names for your middleware functions. The name should clearly indicate what the middleware does.
- Handle errors properly. Always catch errors and pass them to the error handling middleware using
next(error). - Use custom request/response types to enhance type safety. Augment the
RequestandResponseinterfaces with custom properties as needed. - Use middleware factories to configure middleware with specific options.
- Document your middleware functions. Explain what the middleware does and how it should be used.
- Test your middleware functions thoroughly. Write unit tests to ensure that your middleware functions are working correctly.
Conclusion
TypeScript significantly enhances the development of Express middleware by adding static typing, improving code maintainability, and catching errors early. By mastering advanced type patterns like custom request/response types, middleware factories, asynchronous middleware, error handling middleware, and request validation middleware, you can build robust, scalable, and type-safe Express applications. Remember to follow best practices to keep your middleware functions small, focused, and well-documented.